前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
  • 基础篇

    • 环境搭建
    • node部署
    • 基础应用
  • 内置模块

    • 1.0 本地路径处理 path
    • 2.0 文件系统操作 fs
    • 3.1 基础调试 console
    • 3.2 本地调试远程服务器上的Node代码
    • 4.1 网络服务 http
    • 4.2 网络服务 http res
    • 4.3 网络服务 http req
    • 4.4 网络服务 http server
    • 4.5 网络服务 http client
    • 4.6 网络服务 https
    • 4.7 网络TCP net
    • 4.8 网络UDP dgram
    • 4.9 域名解析 dns
    • 5.0 网络地址解析 url
    • 5.1 URL查询字符串 querystring
    • 6.1 流操作 stream
    • 6.2 逐行读取 readline
    • 7.1 进程相关 process
    • 7.2 子进程 child
    • 8.1 二进制数据 buffer
    • 8.2 二进制解码 string_decoder
    • 9.1 事件机制 events
    • 9.2 实用工具模块 util
    • 9.3 数据加密 crypto
    • 9.4 MD5入门介绍及crypto模块的应用
    • 9.4 资源压缩 zlib
    • 9.5 集群 cluster
    • 9.6 v8
  • 进阶篇

    • 5分钟入门非对称加密用法
    • cluster
    • cookie_parser深入
    • crypto模块之理论篇
    • express+cookie_parser签名机制深入剖析
    • express+session实现简易身份认证
    • https
    • log4js入门实例
    • node8_napi
    • 使用 async 控制并发
    • 使用 eventproxy 控制并发
    • 使用 superagent 与 cheerio 完成简单爬虫
    • 基于express+muter的文件上传
    • 将图片转成datauri嵌入到html
    • 常用中间件 body_parser 实现解析
    • 日志模块morgan
    • 服务端字符编解码&乱码处理 charset_enc_dec
    • 测试用例mocha,should,istanbul
    • 调试日志打印debug模块
  • Express

    • 1.1 Express概览篇
    • 1.2 Express
  • Koa2

    • 1.0 koa2概览篇
    • 1.1 快速开始
    • 1.2 async await使用
    • 1.3 koa2简析结构
    • 1.4 koa中间件开发与使用
    • 10.1 单元测试
    • 11.1 开发debug
    • 12.1 快速启动
    • 12.2 框架设计
    • 12.3 分层操作
    • 12.4 数据库设计
    • 12.5 路由设计
    • 12.6 webpack4环境搭建
    • 12.7 使用react
    • 12.8 登录注册功能实现
    • 12.9 session登录态判断处理
    • 13.1 import export使用
    • 2.1 原生koa2实现路由
    • 2.2 koa router中间
    • 3.1 GET请求数据获取
    • 3.2 POST请求数据获取
    • 3.3 koa bodyparser中间件
    • 4.1 原生koa2实现静态资源服务器
    • 4.2 koa static中间件
    • 5.1 koa2使用cookie
    • 5.2 koa2实现session
    • 6.1 koa2加载模板引擎
    • 6.2 ejs模板引擎
    • 7.1 busboy模块
    • 7.2 上传文件简单实现
    • 7.3 异步上传图片实现
    • 8.1 mysql模块
    • 8.2 async await封装使用mysql
    • 8.3 项目建表初始化
    • 9.1 原生koa2实现JSONP
    • 9.2 koa jsonp中间件
  • 其他

    • 操作数据库
    • Session 与 Token
    • Cookie、Session、Token、JWT
    • Socket

# 网络服务 http req

30 秒速记

  • req 是 http.IncomingMessage:服务端代表收到的请求,客户端代表收到的响应
  • 它是可读流:请求头在对象上直接读,请求体要按流读(data / end 或 for await)
  • URL、请求头、请求体全来自外部,都不可信,要校验和限长
  • 请求头的键全是小写;重复头有的丢弃、有的合并,Set-Cookie 是数组
  • 判断客户端提前断开:res.on('close') 时看 res.writableFinished

req 就是一个 http.IncomingMessage 对象,你可以把它理解成「收到的那封信」:信封上的东西(方法、地址、请求头)直接能读,信里的内容(请求体)要当流慢慢读。 服务端回调里的 req 是客户端发来的请求,http.get 回调里的 res 是服务端返回的响应,两个是同一个类,只是方向不同。用的时候我最在意两件事:一是所有字段都来自外部,不能直接信;二是请求体必须读完或者明确丢弃,不然连接会一直挂着。

理解「网络服务 http req」时,要先明确输入、运行阶段和可观察输出。这里的交互实验会分别执行正常路径与失败路径,并把 Node.js 的关键状态变化和同屏代码对应起来;不能只记命令名称。

工程中还要验证退出码、资源清理和异常输入。属于 network 场景的配置应保持最小可复现,并在开发环境与 CI 中使用相同命令复跑,避免把平台差异或隐式默认值带到线上。

http 模块里请求和响应各有一个核心对象:req 是 http.IncomingMessage,res 是 http.ServerResponse。IncomingMessage 同时承担两个角色:在服务端它是客户端发来的请求,在客户端(http.get / http.request)它是服务端返回的响应。

const http = require('http');

http.createServer(async (req, res) => {
  // 信封上的信息:直接读
  console.log(req.method, req.url, req.httpVersion); // GET /hello?a=1 1.1
  console.log(req.headers['user-agent']);           // 键全是小写

  // 信里的内容:按流读,限制大小
  const chunks = [];
  let size = 0;
  for await (const chunk of req) {
    size += chunk.length;
    if (size > 1e6) { res.writeHead(413).end(); return req.destroy(); }
    chunks.push(chunk);
  }
  const body = Buffer.concat(chunks).toString('utf8');

  res.end(`got ${body.length} chars`);
}).listen(3000);
@前端进阶之旅: 代码已经复制到剪贴板

记住三件事:所有字段都是外部输入,要校验;请求体要读完或者明确丢弃(req.resume()),否则 keep-alive 连接没法复用;客户端提前断开时,要把取消传给下游任务,别让服务端继续做无用功。

面试官追问

追问 1服务端回调里的 req 和 http.get 回调里的 res 是同一个类吗?
参考回答

是,都是 http.IncomingMessage,都是可读流。区别在方向:前者有 url、method,后者有 statusCode、statusMessage。

追问 2为什么请求体不能像 req.headers 一样直接取?
参考回答

请求头在请求开头就到齐了,请求体可能很大、分多次到达,Node.js 不会帮你全读进内存。要自己按流读,for await (const chunk of req) 是最简洁的写法。

追问 3客户端请求到一半关了页面,服务端怎么知道?
参考回答

新版本 Node.js 推荐 res.on('close', () => { if (!res.writableFinished) abort() })。req 上的 aborted 事件在 Node.js 17 左右已经废弃,新代码别再依赖它。

追问 4req.headers 里两个同名头会怎样?
参考回答

看字段:Content-Type、Host 这类只保留第一个;Set-Cookie 是数组;其他大多用 , 拼成一个字符串。要看原始样子用 req.rawHeaders,Node.js 18.3 起还有 req.headersDistinct 全部给数组。

# 概览

30 秒速记

  • 服务端 createServer((req, res) => {}) 里的 req 和客户端 http.get(url, res => {}) 里的 res 都是 IncomingMessage
  • 服务端那个 = 收到的请求 → 读 method、url、headers、请求体
  • 客户端那个 = 收到的响应 → 读 statusCode、headers、响应体
  • 变量名不重要,看它是谁「收到」的消息

IncomingMessage 可以理解成「进来的消息」:服务端收到请求、客户端收到响应,拿到的都是它。 所以服务端回调里叫 req,客户端 http.get 回调里叫 res,类型其实一样。区别是消息方向:请求里有 url 和 method,响应里有 statusCode。我见过有人在服务端读 req.statusCode 拿到 undefined 还以为是框架的问题,其实是读错了方向。

本文的重点会放在req这个对象上。前面已经提到,它其实是http.IncomingMessage实例,在服务端、客户端作用略微有差异

  • 服务端处:获取请求方的相关信息,如request header等。
  • 客户端处:获取响应方返回的相关信息,如statusCode等。

服务端例子:

// 下面的 req
var http = require('http');
var server = http.createServer(function(req, res){
    console.log(req.headers);
    res.end('ok');
});
server.listen(3000);
@前端进阶之旅: 代码已经复制到剪贴板

客户端例子

// 下面的res
var http = require('http');
http.get('http://127.0.0.1:3000', function(res){
    console.log(res.statusCode);
});
@前端进阶之旅: 代码已经复制到剪贴板

面试官追问

追问 1同事说服务端的 req 和 http.get 回调里的 res 类型不一样,对吗?
参考回答

不对,两个都是 http.IncomingMessage。只是一个是收到的请求、一个是收到的响应,能用的字段不同。

追问 2订单服务要记录调用方的 User-Agent,探活脚本要拿返回状态,分别从哪取?
参考回答

订单服务读 req.headers['user-agent'],探活脚本在 http.get 回调里读 res.statusCode。

追问 3在服务端读 req.statusCode 会得到什么?
参考回答

undefined,statusCode 只有响应方向的 IncomingMessage 才有值。服务端要设状态码是往 res(ServerResponse)上设。

追问 4TypeScript 里这两个对象怎么标类型?
参考回答

都标 http.IncomingMessage。业务层更好的做法是在入口把它转成自己的 { method, path, query } 结构,下游就不用关心原始对象了。

# 属性/方法/事件 分类

30 秒速记

  • 两端共有:headers、rawHeaders、httpVersion、socket、destroy()、setTimeout()、close 事件
  • 服务端特有:url、method;客户端特有:statusCode、statusMessage
  • headers 键名小写、重复头已处理;rawHeaders 是 [名, 值, 名, 值] 扁平数组,保留原始大小写和顺序
  • aborted 事件新版本已废弃,断开检测改用 close 配合状态判断
  • req.socket.remoteAddress 是直连方地址,挂了代理就是代理的 IP

IncomingMessage 的成员分两类:两端都有的通用部分,和只在某一端有意义的部分。 通用的有 headers、rawHeaders、httpVersion、socket,以及 destroy()、setTimeout();服务端特有 url 和 method,客户端特有 statusCode 和 statusMessage。实际写代码最常用的是 headers 和 rawHeaders 的区别:前者键名统一小写、方便取值,后者保留原貌、适合审计和排查。

http.IncomingMessage的属性/方法/事件 不是特别多,按照是否客户端/服务端 特有的,下面进行简单归类。可以看到

  • 服务端处特有:url
  • 客户端处特有:statusCode、statusMessage
类型 名称 服务端 客户端
事件 aborted ✓ ✓
事件 close ✓ ✓
属性 headers ✓ ✓
属性
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
  • 基础篇

    • 环境搭建
    • node部署
    • 基础应用
  • 内置模块

    • 1.0 本地路径处理 path
    • 2.0 文件系统操作 fs
    • 3.1 基础调试 console
    • 3.2 本地调试远程服务器上的Node代码
    • 4.1 网络服务 http
    • 4.2 网络服务 http res
    • 4.3 网络服务 http req
      • 概览
      • 属性/方法/事件 分类
      • 服务端的例子
        • 例子一:获取httpVersion/method/url
        • 例子二:获取get请求参数
        • 例子三:获取post请求参数
      • 客户端处例子
      • 事件对比:aborted、close
      • 信息量略大的 .destroy()
      • 不常用属性
      • 写在后面
      • 相关链接
    • 4.4 网络服务 http server
    • 4.5 网络服务 http client
    • 4.6 网络服务 https
    • 4.7 网络TCP net
    • 4.8 网络UDP dgram
    • 4.9 域名解析 dns
    • 5.0 网络地址解析 url
    • 5.1 URL查询字符串 querystring
    • 6.1 流操作 stream
    • 6.2 逐行读取 readline
    • 7.1 进程相关 process
    • 7.2 子进程 child
    • 8.1 二进制数据 buffer
    • 8.2 二进制解码 string_decoder
    • 9.1 事件机制 events
    • 9.2 实用工具模块 util
    • 9.3 数据加密 crypto
    • 9.4 MD5入门介绍及crypto模块的应用
    • 9.4 资源压缩 zlib
    • 9.5 集群 cluster
    • 9.6 v8
  • 进阶篇

    • 5分钟入门非对称加密用法
    • cluster
    • cookie_parser深入
    • crypto模块之理论篇
    • express+cookie_parser签名机制深入剖析
    • express+session实现简易身份认证
    • https
    • log4js入门实例
    • node8_napi
    • 使用 async 控制并发
    • 使用 eventproxy 控制并发
    • 使用 superagent 与 cheerio 完成简单爬虫
    • 基于express+muter的文件上传
    • 将图片转成datauri嵌入到html
    • 常用中间件 body_parser 实现解析
    • 日志模块morgan
    • 服务端字符编解码&乱码处理 charset_enc_dec
    • 测试用例mocha,should,istanbul
    • 调试日志打印debug模块
  • Express

    • 1.1 Express概览篇
    • 1.2 Express
  • Koa2

    • 1.0 koa2概览篇
    • 1.1 快速开始
    • 1.2 async await使用
    • 1.3 koa2简析结构
    • 1.4 koa中间件开发与使用
    • 10.1 单元测试
    • 11.1 开发debug
    • 12.1 快速启动
    • 12.2 框架设计
    • 12.3 分层操作
    • 12.4 数据库设计
    • 12.5 路由设计
    • 12.6 webpack4环境搭建
    • 12.7 使用react
    • 12.8 登录注册功能实现
    • 12.9 session登录态判断处理
    • 13.1 import export使用
    • 2.1 原生koa2实现路由
    • 2.2 koa router中间
    • 3.1 GET请求数据获取
    • 3.2 POST请求数据获取
    • 3.3 koa bodyparser中间件
    • 4.1 原生koa2实现静态资源服务器
    • 4.2 koa static中间件
    • 5.1 koa2使用cookie
    • 5.2 koa2实现session
    • 6.1 koa2加载模板引擎
    • 6.2 ejs模板引擎
    • 7.1 busboy模块
    • 7.2 上传文件简单实现
    • 7.3 异步上传图片实现
    • 8.1 mysql模块
    • 8.2 async await封装使用mysql
    • 8.3 项目建表初始化
    • 9.1 原生koa2实现JSONP
    • 9.2 koa jsonp中间件
  • 其他

    • 操作数据库
    • Session 与 Token
    • Cookie、Session、Token、JWT
    • Socket
完整面试题地址:
作者:程序员poetry
扫码关注作者公众号:「前端进阶之旅」 每天分享技术干货
前端进阶之旅公众号二维码

网络服务 http req|Nodejs专题系列

# 网络服务 http req

30 秒速记

  • req 是 http.IncomingMessage:服务端代表收到的请求,客户端代表收到的响应
  • 它是可读流:请求头在对象上直接读,请求体要按流读(data / end 或 for await)
  • URL、请求头、请求体全来自外部,都不可信,要校验和限长
  • 请求头的键全是小写;重复头有的丢弃、有的合并,Set-Cookie 是数组
  • 判断客户端提前断开:res.on('close') 时看 res.writableFinished

req 就是一个 http.IncomingMessage 对象,你可以把它理解成「收到的那封信」:信封上的东西(方法、地址、请求头)直接能读,信里的内容(请求体)要当流慢慢读。 服务端回调里的 req 是客户端发来的请求,http.get 回调里的 res 是服务端返回的响应,两个是同一个类,只是方向不同。用的时候我最在意两件事:一是所有字段都来自外部,不能直接信;二是请求体必须读完或者明确丢弃,不然连接会一直挂着。

理解「网络服务 http req」时,要先明确输入、运行阶段和可观察输出。这里的交互实验会分别执行正常路径与失败路径,并把 Node.js 的关键状态变化和同屏代码对应起来;不能只记命令名称。

工程中还要验证退出码、资源清理和异常输入。属于 network 场景的配置应保持最小可复现,并在开发环境与 CI 中使用相同命令复跑,避免把平台差异或隐式默认值带到线上。

http 模块里请求和响应各有一个核心对象:req 是 http.IncomingMessage,res 是 http.ServerResponse。IncomingMessage 同时承担两个角色:在服务端它是客户端发来的请求,在客户端(http.get / http.request)它是服务端返回的响应。

const http = require('http');

http.createServer(async (req, res) => {
  // 信封上的信息:直接读
  console.log(req.method, req.url, req.httpVersion); // GET /hello?a=1 1.1
  console.log(req.headers['user-agent']);           // 键全是小写

  // 信里的内容:按流读,限制大小
  const chunks = [];
  let size = 0;
  for await (const chunk of req) {
    size += chunk.length;
    if (size > 1e6) { res.writeHead(413).end(); return req.destroy(); }
    chunks.push(chunk);
  }
  const body = Buffer.concat(chunks).toString('utf8');

  res.end(`got ${body.length} chars`);
}).listen(3000);
@前端进阶之旅: 代码已经复制到剪贴板

记住三件事:所有字段都是外部输入,要校验;请求体要读完或者明确丢弃(req.resume()),否则 keep-alive 连接没法复用;客户端提前断开时,要把取消传给下游任务,别让服务端继续做无用功。

面试官追问

追问 1服务端回调里的 req 和 http.get 回调里的 res 是同一个类吗?
参考回答

是,都是 http.IncomingMessage,都是可读流。区别在方向:前者有 url、method,后者有 statusCode、statusMessage。

追问 2为什么请求体不能像 req.headers 一样直接取?
参考回答

请求头在请求开头就到齐了,请求体可能很大、分多次到达,Node.js 不会帮你全读进内存。要自己按流读,for await (const chunk of req) 是最简洁的写法。

追问 3客户端请求到一半关了页面,服务端怎么知道?
参考回答

新版本 Node.js 推荐 res.on('close', () => { if (!res.writableFinished) abort() })。req 上的 aborted 事件在 Node.js 17 左右已经废弃,新代码别再依赖它。

追问 4req.headers 里两个同名头会怎样?
参考回答

看字段:Content-Type、Host 这类只保留第一个;Set-Cookie 是数组;其他大多用 , 拼成一个字符串。要看原始样子用 req.rawHeaders,Node.js 18.3 起还有 req.headersDistinct 全部给数组。

# 概览

30 秒速记

  • 服务端 createServer((req, res) => {}) 里的 req 和客户端 http.get(url, res => {}) 里的 res 都是 IncomingMessage
  • 服务端那个 = 收到的请求 → 读 method、url、headers、请求体
  • 客户端那个 = 收到的响应 → 读 statusCode、headers、响应体
  • 变量名不重要,看它是谁「收到」的消息

IncomingMessage 可以理解成「进来的消息」:服务端收到请求、客户端收到响应,拿到的都是它。 所以服务端回调里叫 req,客户端 http.get 回调里叫 res,类型其实一样。区别是消息方向:请求里有 url 和 method,响应里有 statusCode。我见过有人在服务端读 req.statusCode 拿到 undefined 还以为是框架的问题,其实是读错了方向。

本文的重点会放在req这个对象上。前面已经提到,它其实是http.IncomingMessage实例,在服务端、客户端作用略微有差异

  • 服务端处:获取请求方的相关信息,如request header等。
  • 客户端处:获取响应方返回的相关信息,如statusCode等。

服务端例子:

// 下面的 req
var http = require('http');
var server = http.createServer(function(req, res){
    console.log(req.headers);
    res.end('ok');
});
server.listen(3000);
@前端进阶之旅: 代码已经复制到剪贴板

客户端例子

// 下面的res
var http = require('http');
http.get('http://127.0.0.1:3000', function(res){
    console.log(res.statusCode);
});
@前端进阶之旅: 代码已经复制到剪贴板

面试官追问

追问 1同事说服务端的 req 和 http.get 回调里的 res 类型不一样,对吗?
参考回答

不对,两个都是 http.IncomingMessage。只是一个是收到的请求、一个是收到的响应,能用的字段不同。

追问 2订单服务要记录调用方的 User-Agent,探活脚本要拿返回状态,分别从哪取?
参考回答

订单服务读 req.headers['user-agent'],探活脚本在 http.get 回调里读 res.statusCode。

追问 3在服务端读 req.statusCode 会得到什么?
参考回答

undefined,statusCode 只有响应方向的 IncomingMessage 才有值。服务端要设状态码是往 res(ServerResponse)上设。

追问 4TypeScript 里这两个对象怎么标类型?
参考回答

都标 http.IncomingMessage。业务层更好的做法是在入口把它转成自己的 { method, path, query } 结构,下游就不用关心原始对象了。

# 属性/方法/事件 分类

30 秒速记

  • 两端共有:headers、rawHeaders、httpVersion、socket、destroy()、setTimeout()、close 事件
  • 服务端特有:url、method;客户端特有:statusCode、statusMessage
  • headers 键名小写、重复头已处理;rawHeaders 是 [名, 值, 名, 值] 扁平数组,保留原始大小写和顺序
  • aborted 事件新版本已废弃,断开检测改用 close 配合状态判断
  • req.socket.remoteAddress 是直连方地址,挂了代理就是代理的 IP

IncomingMessage 的成员分两类:两端都有的通用部分,和只在某一端有意义的部分。 通用的有 headers、rawHeaders、httpVersion、socket,以及 destroy()、setTimeout();服务端特有 url 和 method,客户端特有 statusCode 和 statusMessage。实际写代码最常用的是 headers 和 rawHeaders 的区别:前者键名统一小写、方便取值,后者保留原貌、适合审计和排查。

http.IncomingMessage的属性/方法/事件 不是特别多,按照是否客户端/服务端 特有的,下面进行简单归类。可以看到

  • 服务端处特有:url
  • 客户端处特有:statusCode、statusMessage
类型 名称 服务端 客户端
事件 aborted ✓ ✓
事件 close ✓ ✓
属性 headers ✓ ✓
属性 rawHeaders ✓ ✓
属性 statusCode ✕ ✓
属性 statusMessage ✕ ✓
属性 httpVersion ✓ ✓
属性 url ✓ ✕
属性 socket ✓ ✓
方法 .destroy() ✓ ✓
方法 .setTimeout() ✓ ✓

面试官追问

追问 1服务端里 req.statusCode 一直是 undefined,同事说这个类明明有这个属性,怎么解释?
参考回答

属性定义在类上,但只有响应方向的消息才会填值。服务端收到的是请求,有的是 url 和 method。

追问 2headers 和 rawHeaders 有什么区别?
参考回答

headers 是对象,键名小写,重复头已经合并或丢弃;rawHeaders 是扁平数组,比如 ['Host', 'a.com', 'X-Id', '1'],原样保留大小写、顺序和重复。业务取值用前者,排查请求被改写时看后者。

追问 3要拿客户端真实 IP,读 req.socket.remoteAddress 可以吗?
参考回答

直连可以,挂了 Nginx 拿到的就是 Nginx 的地址。这时读 X-Forwarded-For,但只能在确认请求来自可信代理时才信,否则谁都能伪造这个头。

追问 4想在请求读到一半时主动停掉,用什么?
参考回答

req.destroy(),会关闭底层连接。常见场景是请求体超过上限时直接掐断,比读完再拒绝省内存。

# 服务端的例子

← 4.2 网络服务 http res4.4 网络服务 http server →

fe